package com.hisense.store.batch.main.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * @author minfanfu
 * @since
 */
public class SplitApk
{
    private HashMap<String, Channel> qudao = new HashMap<String, Channel>();// 渠道号，渠道名
    private String curPath;// 当前文件夹路径
    private String apkName;
    private String keyFile;
    private String keyPasswd;

    public SplitApk(String apkName, String keyFile, String keyPasswd)
    {// 构造函数接受参数
        this.curPath = new File("").getAbsolutePath();
        this.apkName = apkName;
        this.keyFile = keyFile;
        this.keyPasswd = keyPasswd;
    }

    public void mySplit()
    {
        getCannelFile();// 获得自定义的渠道号
        modifyChannel();// 解包 - 打包 - 签名
    }

    /**
     * 获得渠道号
     */
    private void getCannelFile()
    {
        File f = new File("channel.properties");// 读取当前文件夹下的channel.txt
        if (f.exists() && f.isFile())
        {
            BufferedReader br = null;
            InputStreamReader isr = null;
            // FileReader fr = null;
            try
            {
                // fr = new FileReader(f);

                isr = new InputStreamReader(new FileInputStream(f), "UTF-8");
                br = new BufferedReader(isr);

                // br = new BufferedReader(fr);
                String line = null;
                while ((line = br.readLine()) != null)
                {

                    if (line.startsWith("//") || line.startsWith("#"))
                    {
                        continue;
                    }
                    print("==INFO 0.==获取渠道成功:" + line);
                    String[] array = line.split("[|]");// 这里是Tab分割
                    Channel chanel = new Channel();
                    if (array.length == 2)
                    {
                        chanel.setVersionName(array[0].trim());
                        chanel.setVersionCode(array[1].trim());

                        qudao.put(array[0].trim(), chanel);// 讲渠道号和渠道名存入HashMap中
                    } else if (array.length == 3)
                    {

                        chanel.setVersionName(array[0].trim());
                        chanel.setVersionCode(array[1].trim());
                        chanel.setFeatureCode(array[2].trim());

                        qudao.put(array[0].trim(), chanel);// 讲渠道号和渠道名存入HashMap中

                    }
                    else if (array.length == 4)
                    {

                        chanel.setVersionName(array[0].trim());
                        chanel.setVersionCode(array[1].trim());
                        chanel.setFeatureCode(array[2].trim());
                        chanel.setAppStoreName(array[3].trim());

                        qudao.put(array[0].trim(), chanel);// 讲渠道号和渠道名存入HashMap中

                    }
                }
            } catch (Exception e)
            {
                e.printStackTrace();
            } finally
            {
                try
                {
                    if (isr != null)
                    {
                        isr.close();
                    }
                    if (br != null)
                    {
                        br.close();
                    }
                } catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
            print("==INFO 1.==获取渠道成功，一共有" + qudao.size()
                + "个渠道======");
        } else
        {
            print("==ERROR==channel.txt文件不存在，请添加渠道文件======");
            return;
        }
    }

    /**
     * apktool解压apk，替换渠道值
     * @throws Exception
     */
    private void modifyChannel()
    {

        // 备份AndroidManifest.xml
        // 获取解压的apk文件名
        String[] apkFilePath = apkName.split("\\\\");
        String shortApkName = apkFilePath[apkFilePath.length - 1];
        String dir = shortApkName.split(".apk")[0];

        String sourceDir = curPath + "\\tmp\\" + dir;

        // 解压 /C 执行字符串指定的命令然后终断
        String cmdUnpack = "cmd.exe /C java -jar " + curPath + "\\lib\\a.jar d -f -s "
            + apkName + " " + sourceDir;
        runCmd(cmdUnpack);
        print("==INFO 2.==解压apk成功，准备移动======");

        File packDir = new File(sourceDir);// 获得解压的apk目录

        String f_mani = packDir.getAbsolutePath() + "\\AndroidManifest.xml";
        String f_mani_bak = curPath + "\\tmp\\AndroidManifest.xml";
        File manifest = new File(f_mani);
        File manifest_bak = new File(f_mani_bak);

        try
        {
            FileUtils.copyFile(manifest, manifest_bak);
            print("==INFO 3.==AndroidManifest移动文件成功");

        } catch (IOException e1)
        {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            // 拷贝文件 -- 此方法慎用，详见http://xiaoych.iteye.com/blog/149328
            manifest.renameTo(manifest_bak);
        }

        for (int i = 0; i < 120; i++)
        {
            if (manifest_bak.exists())
            {
                break;
            }
            try
            {
                Thread.sleep(1000);
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }

        if (manifest_bak.exists())
        {
            print("==INFO 4.==移动文件成功======");
        } else
        {
            print("==ERROR==移动文件失败======");
        }

        // 创建生成结果的目录
        File f = new File("apk");
        if (!f.exists())
        {
            f.mkdir();
        }

        String resDirSource = curPath + "\\tmp\\" + dir + "\\res";

        File resDirFrom = new File(resDirSource);// 获得解压的res目录

        String resDirBak = curPath + "\\tmp\\res_bak";

        File resDirTo = new File(resDirBak);// 获得解压的apk目录

        try
        {
            FileUtils.copyDirectory(resDirFrom, resDirTo);
        } catch (IOException e)
        {

            e.printStackTrace();
        }

        if (resDirTo.exists())
        {
            print("==INFO 5.==备份资源文件成功======");
        } else
        {
            print("==ERROR==移动资源文件失败======");
            return;
        }

        /*
         * 遍历map，复制manifest进来，修改后打包，签名，存储在对应文件夹中
         */
        for (Map.Entry<String, Channel> entry : qudao.entrySet())
        {

            // 资源文件是否修改过
            boolean isResChanged = false;

            String versionname = entry.getKey();
            Channel channel = entry.getValue();
            print("==INFO 6. == 正在生成包: " + versionname
                + " ======");
            BufferedReader br = null;
            FileReader fr = null;
            FileWriter fw = null;
            // 步骤1：处理manifest文件。
            try
            {

                // 每次从备份文件读取数据
                fr = new FileReader(manifest_bak);
                br = new BufferedReader(fr);
                String line = null;
                StringBuffer sb = new StringBuffer();

                boolean isToFeatureCodeFind = true;
                String featureCode = channel.getFeatureCode();
                if (featureCode == null || "".equals(featureCode.trim()) || featureCode.length() != 24)
                {
                    isToFeatureCodeFind = false;
                    print("==INFO 7. ==featurecode不符規則，不会进行替换 " + featureCode);
                }

                while ((line = br.readLine()) != null)
                {

                    String matchName = "android:versionName=\"(.*?)\"";
                    String matchCode = "android:versionCode=\"(.*?)\"";
                    String matchFeatureCode = "android:value=\"(.*?)\"";

                    Pattern pat = Pattern.compile(matchName);
                    Matcher m = pat.matcher(line);
                    while (m.find())
                    {
                        String signatureServer = m.group();
                        String signature = m.group(1);

                        String s = signatureServer.replace(signature, versionname);
                        line = line.replace(signatureServer, s);

                        print("==INFO 8. ==Replace versionname:" + signatureServer + " " + s);
                    }

                    pat = Pattern.compile(matchCode);
                    m = pat.matcher(line);
                    while (m.find())
                    {
                        String signatureServer = m.group();
                        String signature = m.group(1);

                        String s = signatureServer.replace(signature, channel.getVersionCode());
                        line = line.replace(signatureServer, s);
                        print("==INFO 9. ==Replace versioncode:" + signatureServer + " " + s);
                    }

                    // 查找featurecode

                    if (isToFeatureCodeFind)
                    {
                        pat = Pattern.compile(matchFeatureCode);
                        m = pat.matcher(line);
                        while (m.find())
                        {
                            String signatureServer = m.group();
                            String signature = m.group(1);
                            String s = signatureServer.replace(signature, featureCode);
                            line = line.replace(signatureServer, s);
                            print("==INFO 10. ==Replace featureCode:" + signatureServer + " " + s + " line:" + line);
                        }
                    }

                    sb.append(line + "\n");
                }

                // 从备份文件读取完数据之后，写会到源文件中
                fw = new FileWriter(f_mani);
                fw.write(sb.toString());

                String appStoreName = channel.getAppStoreName();

                isResChanged = processAppStoreName(appStoreName, resDirBak, resDirSource);

            } catch (Exception e)
            {
                e.printStackTrace();
                print("==ERROR 10.7.1 ==Replace appStorename error");
            } finally
            {
                try
                {
                    if (fr != null)
                    {
                        fr.close();
                    }
                } catch (IOException e)
                {
                    e.printStackTrace();
                    print("==ERROR 10.7.1 ==Replace appStorename error");
                }
                try
                {
                    if (br != null)
                    {
                        br.close();
                    }
                } catch (IOException e)
                {
                    e.printStackTrace();
                    print("==ERROR 10.7.1 ==Replace appStorename error");
                }
                try
                {
                    if (fw != null)
                    {
                        fw.close();
                    }
                } catch (IOException e)
                {
                    e.printStackTrace();
                    print("==ERROR 10.7.1 ==Replace appStorename error");
                }
            }

            String res[] = versionname.split("[.]");

            if (res != null && res.length > 1)
            {

                String resDir = curPath + "\\res\\" + res[res.length - 1];

                File resDirs = new File(resDir);// 资源目录是否存在

                if (resDirs.exists() && resDirs.isDirectory())
                {
                    print("==INFO 11.1 图片资源文件存在可以进行替换:" + resDir);
                    isResChanged = true;
                    // 进行操作将resDirs中存在的图片资源，拷贝粘贴到 resDirFrom目录中进行覆盖

                    // drawable-hdpi
                    // drawable-zh-rCN-hdpi
                    // drawable-zh-rTW-hdpi

                    if (resDirFrom.exists() && resDirFrom.isDirectory())
                    {
                        File[] resDirFroms = resDirFrom.listFiles();
                        if (resDirFroms != null)
                        {
                            for (int i = 0; i < resDirFroms.length; i++)
                            {
                              boolean flag=  processResExchange(resDir, resDirSource, resDirFroms[i].getName());
                           
                              if(!flag)
                              {
                                  print("==ERROR 11.1.1 图片资源文替换失败，终止后续步骤");  
                              }
                            
                            }

                        }
                    }

                }
                else
                {
                    print("==INFO 11.1 图片资源文件不存在，无需替换");

                }

            }

            print("==INFO 11.2 == 准备打包1: " + entry.getKey()
                + " ======");

            // 打包 - 生成未签名的包
            String unsignApk = curPath + "\\tmp\\" + versionname + "_" + dir + "_un.apk";
            String cmdPack = String.format(
                "cmd.exe /C java -jar " + curPath + "\\lib\\a.jar b %s %s", sourceDir, unsignApk);
            runCmd(cmdPack);

            print("==INFO 12. == 打包完成: " + unsignApk + " dir:" + dir);

            print("==INFO 13. == 开始签名: " + entry.getKey()
                + " ======" + " dir:" + dir);
            // 签名
            String signApk = "./apk/" + versionname + "_" + dir + ".apk";
            String alignApk = "./apk/" + "AppStore" + versionname + "-release" + ".apk";

            File alignApkFile = new File(alignApk);

            if (alignApkFile.exists())
            {

                print("==INFO 14. == 删除已存在的文件: " + entry.getKey()
                    + " ======");
                alignApkFile.delete();
            }

            String cmdKey =
                String
                    .format(
                        "cmd.exe /C java -jar " + curPath + "\\lib\\b.jar " + curPath + "\\conf\\a " + curPath
                            + "\\conf\\b %s %s",
                        unsignApk, signApk);

            runCmd(cmdKey);
            print("==INFO 15. == 签名成功: " + entry.getKey()
                + " ======");

            // 对签名的apk进行优化
            String cmdKey1 =
                String
                    .format(
                        "cmd.exe /C zipalign 4 %s %s",
                        signApk, alignApk);

            runCmd(cmdKey1);
            print("==INFO 16. == 优化成功: " + entry.getKey()
                + " ======");

            // 删除未签名的包
            File unApk = new File(unsignApk);
            unApk.delete();

            // 删除未优化的签名的包
            File signApk1 = new File(signApk);
            signApk1.delete();

            if (isResChanged)
            {

                print("==INFO 17. ==资源文件已经修改过，从备份文件进行恢复=" + entry.getKey() + "文件打包生成完毕");
                try
                {

                    // 删除原来的res文件夹，重新拷贝
                    cmdKey = String.format("cmd.exe /C rd /s/q %s", resDirSource);
                    runCmd(cmdKey);

                    print("==INFO 17.1 先删除已经修改的res文件夹：" + resDirSource);

                    FileUtils.copyDirectory(resDirTo, resDirFrom);

                    print("==INFO 17.2 从备份中回复，备份文件为：" + resDirTo.getPath());

                } catch (Exception e)
                {

                    e.printStackTrace();

                    print("==ERROR 17.3 文件恢复失败");
                    return;
                }

            }
            else
            {
                print("==INFO 17. ==资源文件没有修改过，无需操作=" + entry.getKey() + "文件打包生成完毕");
            }

        }

        // 删除中途文件
        String cmdKey = String.format("cmd.exe /C rd /s/q %s", sourceDir);
        runCmd(cmdKey);

        // 删除资源文件文件
        String cmdKey1 = String.format("cmd.exe /C rd /s/q %s", resDirBak);
        runCmd(cmdKey1);

        manifest_bak.delete();

        print("==INFO 18. == 完成 ======");
    }

    private boolean processAppStoreName(String appStoreName, String resDirBak, String resDirSource)
    {

        print("==INFO 10.1. ==processAppStoreName begin:" + appStoreName + " " + resDirBak + " " + resDirSource);

        if (appStoreName == null || "".equals(appStoreName.trim()))
        {
            return false;
        }

        // 英*中*繁
        String[] names = appStoreName.split("#");

        for (int i = 0; i < names.length; i++)
        {
            print("==INFO 10.1.1 ==Replace appStorename:" + names[i] + " " + i);
            if (names[i] == null || "".equals(names[i].trim()) || "0".equals(names[i].trim()))
            {// 不进行替换名称
                print("==INFO 10.1.2 ==Replace appStorename:" + names[i]);

                continue;
            }

            String manifest_bak = "";
            String f_mani = "";

            if (i == 0)
            {// 英,"\\tmp\\res_bak";
                manifest_bak = resDirBak + "\\values\\strings.xml";
                f_mani = resDirSource + "\\values\\strings.xml";

            } else if (i == 1)
            {// 中
                manifest_bak = resDirBak + "\\values-zh-rCN\\strings.xml";
                f_mani = resDirSource + "\\values-zh-rCN\\strings.xml";

            } else if (i == 2)
            {// 繁

                manifest_bak = resDirBak + "\\values-zh-rTW\\strings.xml";
                f_mani = resDirSource + "\\values-zh-rTW\\strings.xml";
            }

            BufferedReader br = null;
            FileReader fr = null;
            FileWriter fw = null;
            // 步骤1：处理manifest文件。
            try
            {

                // 每次从备份文件读取数据
                fr = new FileReader(manifest_bak);
                br = new BufferedReader(fr);
                String line = null;
                StringBuffer sb = new StringBuffer();

                while ((line = br.readLine()) != null)
                {

                    String matchName = "<string name=\"app_store_name\">(.*?)</string>";

                    Pattern pat = Pattern.compile(matchName);
                    Matcher m = pat.matcher(line);
                    while (m.find())
                    {
                        String signatureServer = m.group();
                        String signature = m.group(1);

                        String s = signatureServer.replace(signature, names[i]);
                        line = line.replace(signatureServer, s);

                        print("==INFO 10.2. ==Replace appStorename:" + signatureServer + " " + s + " i:" + i + " "
                            + names.length);
                    }

                    sb.append(line + "\n");
                }

                // 从备份文件读取完数据之后，写会到源文件中
                fw = new FileWriter(f_mani);
                fw.write(sb.toString());

            } catch (Exception e)
            {
                e.printStackTrace();
                print("==ERROR 10.3. ==Replace appStorename error");

            } finally
            {
                if (fr != null)
                {
                    try
                    {
                        fr.close();
                    } catch (IOException e)
                    {
                        e.printStackTrace();
                        print("==ERROR 10.4. ==Replace appStorename error");
                    }
                }

                if (br != null)
                {
                    try
                    {
                        br.close();
                    } catch (IOException e)
                    {
                        e.printStackTrace();
                        print("==ERROR 10.5. ==Replace appStorename error");
                    }
                }

                if (fw != null)
                {
                    try
                    {
                        fw.close();
                    } catch (IOException e)
                    {
                        e.printStackTrace();
                        print("==ERROR 10.6. ==Replace appStorename error");
                    }
                }

            }

        }

        return true;

    }

    /**
     * 处理图片资源替换等
     * @param resDir
     * @param resDirSource
     * @param fileDir
     * @since 3.8
     */
    private boolean processResExchange(String resDir, String resDirSource, String fileDir)
    {

        String drawable_hdpi = resDir + "\\" + fileDir;
        File drawable_hdpi_file = new File(drawable_hdpi);

        String drawable_hdpi_source = resDirSource + "\\" + fileDir;
        File drawable_hdpi_source_file = new File(drawable_hdpi_source);

        // 保存名称前半部分，文件
        HashMap<String, File> drawable_hdpi_map = new HashMap<String, File>();

        // 将源文件保存到hashmap中,需要两边都存在,且是文件夹才进行操作
        if (drawable_hdpi_source_file.exists() && drawable_hdpi_source_file.isDirectory()
            && drawable_hdpi_file.exists() && drawable_hdpi_file.isDirectory())
        {
            File[] filesSrc = drawable_hdpi_source_file.listFiles();

            if (filesSrc != null)
            {
                for (int i = 0; i < filesSrc.length; i++)
                {
                    // print("==INFO 11.1.1 fileName " + files[i].getName() + " "
                    // + files[i].getName().split("[.]")[0]);

                    drawable_hdpi_map.put(filesSrc[i].getName().split("[.]")[0], filesSrc[i]);
                }
            }

            // 过滤将要修改的文件

            File[] files = drawable_hdpi_file.listFiles();

            if (files != null)
            {
                for (int i = 0; i < files.length; i++)
                {
                    String key = files[i].getName().split("[.]")[0];

                    print("==INFO 11.1.2 fileName " + files[i].getName() + " " + key);
                    if (drawable_hdpi_map.containsKey(key))
                    {
                        File file = drawable_hdpi_map.get(key);
                        if (file.delete())
                        {
                            print("==INFO 11.1.3 delete file: " + file.getAbsolutePath());

                            try
                            {
                                FileUtils.copyFile(files[i], file);

                                print("==INFO 11.1.4 copy file from:" + files[i].getAbsolutePath() + " to:"
                                    + file.getAbsolutePath());

                            } catch (Exception e)
                            {
                                e.printStackTrace();
                                print("==INFO 11.1.5 error in copy ");
                                return false;
                                
                            }
                        }

                    }

                }
            }

        }
        
        
        return true;

    }

    class FilePrefixFilter implements FilenameFilter
    {
        private String type;

        public FilePrefixFilter(String type)
        {
            this.type = type;
        }

        public boolean accept(File dir, String name)
        {
            return name.startsWith(type);
        }
    }

    private String getAbsPath(File file)
    {

        String absolutePath = file.getAbsolutePath();
        String splits[] = absolutePath.split("\\\\");
        int length = splits.length;
        if (length >= 2)
        {
            print(splits[length - 2] + "/" + splits[length - 1]);
            return splits[length - 2] + "/" + splits[length - 1];
        }

        return "";
    }

    public String getAttrByNode(String name, String attrName, Node node)
    {
        NodeList list = node.getChildNodes();
        // print("---"+list.getLength());
        String result = "";
        Node child = null;
        for (int innerLoop = 0; innerLoop < list.getLength(); innerLoop++)
        {
            child = list.item(innerLoop);
            if (child instanceof Element)
            {
                if ((child != null) && (child.getNodeName() != null)
                    && (child.getNodeName().equals(name)))
                {
                    // 遍历整个xml某节点指定的属性
                    NamedNodeMap attrs = child.getAttributes();
                    if (attrs.getLength() > 0 && attrs != null)
                    {
                        Node attr = attrs.getNamedItem(attrName);
                        result = attr.getNodeValue();
                    }
                }
            }
        }
        return result;
    }

    /**
     * 执行指令
     * @param cmd
     */
    private void runCmd(String cmd)
    {
        Runtime rt = Runtime.getRuntime();
        BufferedReader br = null;
        InputStreamReader isr = null;
        try
        {
            Process p = rt.exec(cmd);
            // p.waitFor();
            isr = new InputStreamReader(p.getInputStream());
            br = new BufferedReader(isr);
            String msg = null;
            while ((msg = br.readLine()) != null)
            {
                print(msg);
            }
        } catch (Exception e)
        {
            e.printStackTrace();
        } finally
        {
            try
            {
                if (isr != null)
                {
                    isr.close();
                }
                if (br != null)
                {
                    br.close();
                }
            } catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

    public static void listAllFiles(String filePath)
    {
        File file = new File(filePath);

        try
        {
            if (file.exists())
            {
                if (file.isDirectory())
                {
                    File[] files = file.listFiles();
                    if (files != null)
                    {
                        for (int i = 0; i < files.length; i++)
                        {

                            if (files[i].isDirectory())
                            {
                                listAllFiles(files[i].getAbsolutePath());
                            } else
                            {
                                print(files[i].getName() + ": " + files[i].getAbsolutePath());
                            }

                        }
                    }
                }
                else
                {
                    print(file.getName() + ": " + file.getAbsolutePath());
                }
            }
            else
            {
                print("请检查路径是否正确，或者检查路径是否有可读权限！");
            }
        } catch (Exception e)
        {
            print("错误:请检查路径是否正确，或者检查路径是否有可读权限！");
            e.printStackTrace();
        }

    }

    public static void print(String msg)
    {

        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        String time = format.format(new Date(System.currentTimeMillis()));

        final int invokeDepth = 1;
        StackTraceElement[] stacks = new Throwable().getStackTrace();
        String className = stacks[invokeDepth].getClassName();
        className = className.substring(className.lastIndexOf(".") + 1);
        String methodName = stacks[invokeDepth].getMethodName();
        int lineNumber = stacks[invokeDepth].getLineNumber();
        StringBuffer sb = new StringBuffer();
        sb.append(className).append(" ").append(methodName)
            .append(" ").append(lineNumber)
            .append(" ").append(time)
            .append(" : ").append(msg);

        System.out.println(sb.toString());

    }

    public static void listAllDirectory(String filePath)
    {
        File file = new File(filePath);

        try
        {
            if (file.exists())
            {
                if (file.isDirectory())
                {
                    File[] files = file.listFiles();
                    if (files != null)
                    {
                        for (int i = 0; i < files.length; i++)
                        {

                            if (files[i].isDirectory())
                            {
                                print(files[i].getName() + ": " + files[i].getAbsolutePath());
                            }

                        }
                    }
                }
                else
                {
                    print(file.getName() + ": " + file.getAbsolutePath());
                }
            }
            else
            {
                print("请检查路径是否正确，或者检查路径是否有可读权限！");
            }
        } catch (Exception e)
        {
            print("请检查路径是否正确，或者检查路径是否有可读权限！");
            e.printStackTrace();
        }

    }

}
